package org.aeon.protocol;


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import org.aeon.config.Config;
import org.aeon.message.Message;

import java.util.List;

/**
 * @author: MissingAeon
 * @date: 2024/1/23 19:29
 * @description: 自定义 消息编解码器
 */
@Slf4j
@ChannelHandler.Sharable
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {

    // 编码
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {
        final ByteBuf out = ctx.alloc().buffer();
        // 添加魔数
        out.writeBytes(new byte[]{'a', 'e', 'o', 'n'});
        // 版本
        out.writeByte(1);
        // 序列化算法 0 jdk 1 json
        // 获取枚举对象的次序
        out.writeByte(Config.getSerializerAlgorithm().ordinal());
        // 指令类型
        out.writeByte(msg.getMessageType());
        // 请求序号
        out.writeInt(msg.getSequenceId());
        // 填充
        out.writeByte(0xff);
        // 获取内容字节数组
        final byte[] bytes = Config.getSerializerAlgorithm().serializer(msg);
        // 正文长度
        out.writeInt(bytes.length);
        // 写入内容
        out.writeBytes(bytes);
        outList.add(out);
    }

    // 解码
    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 4字节
        int magicNum = in.readInt();
        if (1634037614 != magicNum) return;
        // 1字节
        byte version = in.readByte();
        // 1字节
        byte serializerType = in.readByte();
        // 1字节
        byte messageType = in.readByte();
        // 4字节
        int sequenceId = in.readInt();
        // 1字节
        in.readByte();
        // 4字节
        int length = in.readInt();
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);
        // 不能指定父类来反序列化创建实例
        final Class<?> messageClass = Message.getMessageClass(messageType);
        final Object message = Serializer.Algorithm.values()[serializerType].deserializer(messageClass, bytes);
        out.add(message);
    }
}
